/*
 * DmtSPIProcess.java
 *
 *  Created on: 2017-5-1
 *      Author: liubo
 */
package com.example.dmtprotocollib;

import android.util.Log;

import com.siecom.nativelibs.rkGpioControlNative;


public class DmtSPIProcess{

	private static final String DMTLogTAG="DMT_POC";
	private static final int EXT_DAT_LEN=3072;
	private static final int BUF_LEN=EXT_DAT_LEN+8;
	private static final int SUM_POS=BUF_LEN-1;
	private static final byte ResPonseHead=0x6A;
	public static final int STATUS_IDLE=0;
	public static final int STATUS_SEND=1;
	public static final int STATUS_RECV_CHECK=2;
	public static final int STATUS_RECV_DATA=3;
	public static final int STATUS_TIMEOUT=4;
	public static final int STATUS_EXTDATA_SIZE_ERROR=5;
	public static final int RETRY_DELAY_MS=5;

	private static final byte[] testdata2={(byte)0x77,(byte)0x6a,(byte)0xa6,(byte)0x00,(byte)0x90,(byte)0x00,(byte)0x04,(byte)0x58,(byte)0x03,(byte)0x04,(byte)0x00,(byte)0x12,(byte)0xea};
	public static final boolean debuglog = true;
	public static final boolean use_hardware=true;//true;//false;

	private byte[] cmdbuf=new byte[BUF_LEN];
	private byte[] resbuf=new byte[BUF_LEN];
	private int retry_count=200;
	private boolean flag_open=false;

	public int Status=STATUS_IDLE;

	int spi_rx_test_count=0;



	public int initializeDMTSignDM(int i_timeout_ms)
	{
		retry_count=i_timeout_ms/RETRY_DELAY_MS;
		return 0;
	}


//    private byte[] Get_CmdPacket(byte[] buf)
//    {
//    	int extendlen=(buf[4]<<8)|buf[5];
//    	byte[] sendbuf=new byte[extendlen+8];
//    	System.arraycopy(buf, 0, sendbuf, 0, 7);
//    	System.arraycopy(buf, 7, sendbuf, 7, extendlen);
//    	sendbuf[7+extendlen]=buf[SUM_POS];
//    	return sendbuf;
//    }

	private int Get_CmdPacket(byte[] buf)
	{
		int extendlen=(buf[4]<<8)|buf[5];
		buf[7+extendlen]=buf[SUM_POS];
		return (8+extendlen);

	}




	private void SPI_PutByte(byte data)
	{
		if(use_hardware)
		{
			int tmp=(int)(data&0xff);
			// rkGpioControlNative.ControlGpio(100, tmp);//向SPI写入数据
		}
	}

	public int SPI_PutBytes(byte[] buf,int len)
	{
		if(buf==null)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG, "SPI Send Error:Buf null error");
			}
			return 1;
		}
		if(len>buf.length)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG, "SPI Send Error:Buf length error");
			}
			return 1;
		}
		if(use_hardware)
		{
			for(int i=0;i<len;i++)
			{
				int tmp=(int)(buf[i]&0xff);
				// rkGpioControlNative.ControlGpio(100, tmp);//向SPI写入数据
			}
		}
		return 0;
	}


	public byte SPI_GetByte()
	{
		if(use_hardware)
		{
			// int tmp=rkGpioControlNative.ReadGpio(99);//读取SPI数据
			// byte data=(byte)(tmp);
			// return data;
			return 0;
		}
		else
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG, "SPI Getbyte");
			}

			if(spi_rx_test_count>testdata2.length)
			{
				spi_rx_test_count=0;
			}
			byte data= testdata2[spi_rx_test_count];
			spi_rx_test_count++;
			return data;
		}
	}


//	public byte[] SPI_GetBytes(int len)
//	{
//		byte[] buf=new byte[len];
//		if(use_hardware)
//		{
//			for(int i=0;i<len;i++)
//			{
//				int tmp=rkGpioControlNative.ReadGpio(99);//读取SPI数据
//				buf[i]=(byte)(tmp);
//			}
//		}
//		return buf;
//	}




	private void SPI_SendCommand()
	{
		int sendlen=Get_CmdPacket(cmdbuf);
		if(sendlen<1)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG, "SPI Send Error:Send length error");
			}
			return ;
		}
		if(debuglog)
		{
			utility.Byte_Log("CMD Pkt:",cmdbuf,sendlen);
		}
		Status=STATUS_SEND;


		if(debuglog)
		{
			Log.d(DMTLogTAG, "SPI Sending...");
		}

		SPI_PutBytes(cmdbuf,sendlen);

		if(debuglog)
		{
			Log.d(DMTLogTAG, "SPI Send Complete");
		}

		Status=STATUS_IDLE;
	}





	private void delay_ms(int time_ms)
	{
		try{
			Thread.sleep(time_ms);
		}
		catch(InterruptedException e)
		{
			Thread.currentThread().interrupt();
		}
	}



	private void SPI_GetRespon()
	{
		int count=retry_count;
		int datalen;
		int retry_times=0;
		byte tmp;
		Status=STATUS_RECV_CHECK;
		while(count>0)
		{
			tmp=SPI_GetByte();
			if(tmp==ResPonseHead)
			{
				Status=STATUS_RECV_DATA;
				resbuf[0]=tmp;
				resbuf[1]=SPI_GetByte();
				resbuf[2]=SPI_GetByte();
				resbuf[3]=SPI_GetByte();
				resbuf[4]=SPI_GetByte();
				resbuf[5]=SPI_GetByte();
				resbuf[6]=SPI_GetByte();
				if(debuglog)
				{
					utility.Byte_Log("GetRSP HeadPkt:",resbuf,7);
				}
				datalen=((int)(resbuf[4]&0xff)<<8)|((int)(resbuf[5]&0xff));
				if(datalen>EXT_DAT_LEN)
				{
					Status=STATUS_EXTDATA_SIZE_ERROR;
					return ;
				}
				if(debuglog)
				{
					if(datalen<0)
					{
						Log.d(DMTLogTAG, "GetRSP Payload datalen="+datalen);
					}
				}

				for(int i=0;i<datalen;i++)
				{
					resbuf[7+i]=SPI_GetByte();
				}
				resbuf[7+datalen]=SPI_GetByte();
				if(debuglog)
				{
					if(datalen>0)
					{
						//utility.Byte_Log("GetRSP Payload 0~7:",resbuf,7,datalen);
						Log.d(DMTLogTAG, "GetRSP Payload datalen="+datalen);
					}
					utility.Byte_Log("GetRSP SUM:",resbuf,datalen+7,1);
				}
				break;
			}
			else		//waiting 5ms try again
			{
				if(debuglog)
				{
					retry_times++;
					byte[] strtmp=new byte[1];
					strtmp[0]=tmp;
					Log.d(DMTLogTAG,"Check Retry="+retry_times+",Data="+utility.bytesToHexString(strtmp));
				}

				delay_ms(5);
				count--;
			}
		}
		if(count<=0)
		{
			/*****************************add by liubo Test SPI Reset****************************************/
			delay_ms(10);
			Restore_SPI(102400);//if ret= 1003, Reset SPI
			Log.d(DMTLogTAG,"SPI Reset");
			/***********************************Test SPI Reset End**********************************/
			Status=STATUS_TIMEOUT;
		}
		else
		{
			Status=STATUS_IDLE;
		}

	}



	public void Restore_SPI(int count)
	{
		while(count>0)
		{
			// rkGpioControlNative.ControlGpio(100, 0x00);
			count--;
		}
	}


	public int getversionDMTSignDM(StringBuffer pchVer)
	{
		int ret;

		ret=DmtProtocol.CmdGetVersion(cmdbuf);
		if(ret!=DmtProtocol.STATUS_OK)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG,"GetCmd error ret="+ret);
			}
			return ret;
		}
		SPI_SendCommand();//send cmd

		delay_ms(100);//waiting process

//        SPI_GetRespon();//recv data
		if(use_hardware)
		{
			SPI_GetRespon();//recv data
		}
		else
		{
			System.arraycopy(TestRspData.GetVersion_Rsp, 0, resbuf, 0, TestRspData.GetVersion_Rsp.length);
		}

		if(Status==STATUS_TIMEOUT)
		{
			ret=DmtProtocol.STATUS_ERR_TIMEOUT;
			return ret;
		}

		byte[] ver_msg=new byte[4];
		ret=DmtProtocol.RspGetVersion(resbuf,ver_msg);
		if(ret==DmtProtocol.STATUS_OK)
		{
			pchVer.append('v');
			pchVer.append(ver_msg[0]);
			pchVer.append('.');
			pchVer.append(ver_msg[1]);
			pchVer.append('.');
			pchVer.append(ver_msg[2]);
			pchVer.append('.');
			pchVer.append(ver_msg[3]);
			if(debuglog)
			{
				utility.Byte_Log("RSP Ver_inf:",ver_msg);
			}
		}
		return ret;
	}


	public int connectDMTSignDM()
	{
		int ret=0;
		byte[] rfu=new byte[4];
		ret=DmtProtocol.CmdOpen(cmdbuf,rfu);
		if(ret!=DmtProtocol.STATUS_OK)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG,"GetCmd error ret="+ret);
			}
			return ret;
		}
		SPI_SendCommand();//send cmd

		delay_ms(100);//waiting process
		if(use_hardware)
		{
			SPI_GetRespon();//recv data
		}
		else
		{
			System.arraycopy(TestRspData.Open_Rsp, 0, resbuf, 0, TestRspData.Open_Rsp.length);
		}
		ret=DmtProtocol.RspOpen(resbuf);

		if(ret==DmtProtocol.STATUS_OK)
		{
			flag_open=true;
		}
		if(Status==STATUS_TIMEOUT)
		{
			ret=DmtProtocol.STATUS_ERR_TIMEOUT;
		}

		return ret;
	}


	public int closeDMTSignDM()
	{
		int ret=0;

		ret=DmtProtocol.CmdClose(cmdbuf);
		if(ret!=DmtProtocol.STATUS_OK)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG,"GetCmd error ret="+ret);
			}
			return ret;
		}
		SPI_SendCommand();//send cmd

		delay_ms(100);//waiting process
		if(use_hardware)
		{
			SPI_GetRespon();//recv data
		}
		else
		{
			System.arraycopy(TestRspData.Close_Rsp, 0, resbuf, 0, TestRspData.Close_Rsp.length);
		}
		ret=DmtProtocol.RspClose(resbuf);

		if(ret==DmtProtocol.STATUS_OK)
		{
			flag_open=false;
		}

		if(Status==STATUS_TIMEOUT)
		{
			ret=DmtProtocol.STATUS_ERR_TIMEOUT;
		}
		return ret;
	}


	public int transSM2Publickey(int bKeyid,byte[] pchPubkey)
	{
		int ret=0;

		if(bKeyid>1||bKeyid<0)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG,"transSM2Publickey error Keyid="+bKeyid);
			}
			return DmtProtocol.STATUS_ERR_OTHER;
		}

		if(bKeyid==0)
		{
			ret=DmtProtocol.CmdTransSM2Key1(cmdbuf);
		}
		else
		{
			ret=DmtProtocol.CmdTransSM2Key2(cmdbuf,pchPubkey);
		}

		if(ret!=DmtProtocol.STATUS_OK)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG,"GetCmd error ret="+ret);
			}
			return ret;
		}
		SPI_SendCommand();//send cmd

		delay_ms(200);//waiting process
		if(use_hardware)
		{
			SPI_GetRespon();//recv data
		}
		else
		{
			if(bKeyid==0)
			{
				System.arraycopy(TestRspData.TransSM2Key1_Rsp, 0, resbuf, 0, TestRspData.TransSM2Key1_Rsp.length);
			}
			else
			{
				System.arraycopy(TestRspData.TransSM2Key2_Rsp, 0, resbuf, 0, TestRspData.TransSM2Key2_Rsp.length);
			}
		}

		if(bKeyid==0)
		{
			ret=DmtProtocol.RspTransSM2Key1(resbuf,pchPubkey);
		}
		else
		{
			ret=DmtProtocol.RspTransSM2Key2(resbuf);
		}

		if(Status==STATUS_TIMEOUT)
		{
			ret=DmtProtocol.STATUS_ERR_TIMEOUT;
		}
		return ret;
	}


	/*
        //pchVerify not use?sm4keymode or sm4keytype?
        public int setSM4PrimaryKey(byte[] pchPrikey)
        {
            int ret=0;

            ret=DmtProtocol.CmdTransSM4Key1(cmdbuf,(byte)0,pchPrikey);
            if(ret!=DmtProtocol.STATUS_OK)
            {
                if(debuglog)
                {
                    Log.d(DMTLogTAG,"GetCmd error ret="+ret);
                }
                return ret;
            }
            SPI_SendCommand();//send cmd

            delay_ms(100);//waiting process
            if(use_hardware)
            {
                SPI_GetRespon();//recv data
            }
            else
            {
                System.arraycopy(TestRspData.TransSM4Key1_Rsp, 0, resbuf, 0, TestRspData.TransSM4Key1_Rsp.length);
            }
            ret=DmtProtocol.RspTransSM4Key1(resbuf,(byte)0,pchPrikey);

            if(Status==STATUS_TIMEOUT)
            {
                ret=DmtProtocol.STATUS_ERR_TIMEOUT;
            }
            return ret;
        }
    */
	public int setSM4PrimaryKey(byte[] pchPrikey,byte[] pchVerify)
	{
		int ret=0;

		ret=DmtProtocol.CmdTransSM4Key1(cmdbuf,(byte)0,pchPrikey);
		if(ret!=DmtProtocol.STATUS_OK)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG,"GetCmd error ret="+ret);
			}
			return ret;
		}
		SPI_SendCommand();//send cmd

		delay_ms(100);//waiting process
		if(use_hardware)
		{
			SPI_GetRespon();//recv data
		}
		else
		{
			System.arraycopy(TestRspData.TransSM4Key1_Rsp, 0, resbuf, 0, TestRspData.TransSM4Key1_Rsp.length);
		}
		ret=DmtProtocol.RspTransSM4Key1(resbuf,(byte)0,pchVerify);

		if(Status==STATUS_TIMEOUT)
		{
			ret=DmtProtocol.STATUS_ERR_TIMEOUT;
		}
		return ret;
	}

	public int startDMTSignDM()
	{
		int ret=0;

		ret=DmtProtocol.CmdStartSign(cmdbuf);
		if(ret!=DmtProtocol.STATUS_OK)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG,"GetCmd error ret="+ret);
			}
			return ret;
		}
		SPI_SendCommand();//send cmd

		delay_ms(200);//waiting process
		if(use_hardware)
		{
			SPI_GetRespon();//recv data
		}
		else
		{
			System.arraycopy(TestRspData.StartSign_Rsp, 0, resbuf, 0, TestRspData.StartSign_Rsp.length);
		}
		ret=DmtProtocol.RspStartSign(resbuf);

		if(Status==STATUS_TIMEOUT)
		{
			ret=DmtProtocol.STATUS_ERR_TIMEOUT;
		}
		return ret;
	}


	public int clearDMTSignDM()
	{
		int ret=0;

		ret=DmtProtocol.CmdCancelSign(cmdbuf);
		if(ret!=DmtProtocol.STATUS_OK)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG,"GetCmd error ret="+ret);
			}
			return ret;
		}
		SPI_SendCommand();//send cmd

		delay_ms(100);//waiting process
		if(use_hardware)
		{
			SPI_GetRespon();//recv data
		}
		else
		{
			System.arraycopy(TestRspData.CancelSign_Rsp, 0, resbuf, 0, TestRspData.CancelSign_Rsp.length);
		}
		ret=DmtProtocol.RspCancelSign(resbuf);

		if(Status==STATUS_TIMEOUT)
		{
			ret=DmtProtocol.STATUS_ERR_TIMEOUT;
		}

		return ret;
	}

	public int endDMTSignDM()
	{
		int ret=0;
		int[] isize=new int[1];
		ret=DmtProtocol.CmdEndSign(cmdbuf);
		if(ret!=DmtProtocol.STATUS_OK)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG,"GetCmd error ret="+ret);
			}
			return ret;
		}
		SPI_SendCommand();//send cmd

		delay_ms(200);//waiting process
		if(use_hardware)
		{
			SPI_GetRespon();//recv data
		}
		else
		{
			System.arraycopy(TestRspData.EndSign_Rsp, 0, resbuf, 0, TestRspData.EndSign_Rsp.length);
		}
		ret=DmtProtocol.RspEndSign(resbuf,isize);//isize not use ?
		if(debuglog)
		{
			if(ret==DmtProtocol.STATUS_OK)
			{
				Log.d(DMTLogTAG,"Cipher Size="+isize[0]);
			}
		}
		if(Status==STATUS_TIMEOUT)
		{
			ret=DmtProtocol.STATUS_ERR_TIMEOUT;
		}

		return ret;
	}


	public int getcipherDMTSignDM (byte[] pchData, int[] pdwLen)
	{
		int ret=0;
		byte[] cdata={0,0,0,0};
		short[] wLen={10};
		int iTotalLen=0;
		boolean overflow=false;
		if(debuglog)
		{
			Log.d(DMTLogTAG,"GetcipherDMTSignDM Start");
		}
		while(wLen[0]>0)
		{

			ret=DmtProtocol.CmdTransEncSign(cmdbuf,cdata);
			if(ret!=DmtProtocol.STATUS_OK)
			{
				if(debuglog)
				{
					Log.d(DMTLogTAG,"GetCmd error ret="+ret);
				}
				return ret;
			}
			SPI_SendCommand();//send cmd

			delay_ms(100);//waiting process
			if(use_hardware)
			{
				SPI_GetRespon();//recv data
			}
			else
			{
//				System.arraycopy(TestRspData.TransEncSign_Rsp, 0, resbuf, 0, TestRspData.TransEncSign_Rsp.length);
			}
			byte[] tmpbuf=new byte[BUF_LEN];
			ret=DmtProtocol.RspTransEncSign(resbuf,wLen,tmpbuf);

			if(ret!=DmtProtocol.STATUS_OK)
			{
				if(debuglog)
				{
					Log.d(DMTLogTAG,"GetcipherDMTSignDM Rsp Error="+ret);
				}
				break;
			}
			if(wLen[0]>0)
			{
				if(debuglog)
				{
					if(wLen[0]<EXT_DAT_LEN)
					{
						Log.d(DMTLogTAG,"Last packet");
					}

				}

				if((iTotalLen + wLen[0])>pchData.length)
				{
					if(debuglog)
					{
						Log.d(DMTLogTAG,"GetcipherDMTSignDM Overflow!");
					}
					overflow=true;
				}
				else
				{
					System.arraycopy(tmpbuf,0,pchData,iTotalLen,wLen[0]);
				}
			}
			iTotalLen += wLen[0];

			delay_ms(50);

			if(debuglog)
			{
				Log.d(DMTLogTAG,"iTotalLen="+iTotalLen+",wLen="+wLen[0]);
			}
			if(!use_hardware)
			{
				break;
			}

		}
		if(debuglog)
		{
			Log.d(DMTLogTAG,"GetcipherDMTSignDM End TotalLen="+iTotalLen);
		}
		pdwLen[0]=iTotalLen;
		if(Status==STATUS_TIMEOUT)
		{
			ret=DmtProtocol.STATUS_ERR_TIMEOUT;
		}
		if(overflow)
		{
			ret=DmtProtocol.STATUS_ERR_OTHER;
		}

		return ret;

	}

/*
	public int resetDMTSignDM()
	{
		int ret=0;

		ret=DmtProtocol.CmdReset(cmdbuf);
		if(ret!=DmtProtocol.STATUS_OK)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG,"GetCmd error ret="+ret);
			}
			return ret;
		}
    	SPI_SendCommand();//send cmd

    	delay_ms(100);//waiting process
    	if(use_hardware)
    	{
    		SPI_GetRespon();//recv data
    	}
    	else
    	{
    		System.arraycopy(TestRspData.Reset_Rsp, 0, resbuf, 0, TestRspData.Reset_Rsp.length);
    	}
    	ret=DmtProtocol.RspReset(resbuf);

        if(Status==STATUS_TIMEOUT)
        {
        	ret=DmtProtocol.STATUS_ERR_TIMEOUT;
        }
        return ret;

	}



	public int getstatusDMTSignDM(byte[] pchCode, byte[]pchDes)
	{
		int ret=0;

		ret=DmtProtocol.CmdGetStatus(cmdbuf);
		if(ret!=DmtProtocol.STATUS_OK)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG,"GetCmd error ret="+ret);
			}
			return ret;
		}
    	SPI_SendCommand();//send cmd

    	delay_ms(100);//waiting process
    	if(use_hardware)
    	{
    		SPI_GetRespon();//recv data
    	}
    	else
    	{
    		System.arraycopy(TestRspData.GetstatusRsp, 0, resbuf, 0, TestRspData.GetstatusRsp.length);
    	}
    	ret=DmtProtocol.RspGetStatus(resbuf,pchCode,pchDes);

        if(Status==STATUS_TIMEOUT)
        {
        	ret=DmtProtocol.STATUS_ERR_TIMEOUT;
        }
        return ret;
	}


	public int isconnectDMTSignDM()
	{
		if(flag_open)
		{
			return DmtProtocol.STATUS_OK;
		}
		else
		{
			return DmtProtocol.STATUS_ERR_OPEN;
		}
	}

	public int updateDMTSignDM()
	{
		int ret=0;
		byte[] cdata=new byte[4];
		ret=DmtProtocol.CmdSetUpdate(cmdbuf);
		if(ret!=DmtProtocol.STATUS_OK)
		{
			if(debuglog)
			{
				Log.d(DMTLogTAG,"GetCmd error ret="+ret);
			}
			return ret;
		}
    	SPI_SendCommand();//send cmd

    	delay_ms(100);//waiting process
    	if(use_hardware)
    	{
    		SPI_GetRespon();//recv data
    	}
    	else
    	{
    		System.arraycopy(TestRspData.UpdateRsp, 0, resbuf, 0, TestRspData.UpdateRsp.length);
    	}
    	ret=DmtProtocol.RspSetUpdate(resbuf);

        if(Status==STATUS_TIMEOUT)
        {
        	ret=DmtProtocol.STATUS_ERR_TIMEOUT;
        }

		return ret;
	}
*/

}

